﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UserRepositoryTest.cs" company="Concept Architecture">
//   (c) 2010 Muhammad Umer Farooq
// </copyright>
// <summary>
//   Defines the UserRepositoryTest type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Hisaab.Data.Tests
{
    using System.Data.Objects;
    using System.Linq;
    using Entities;
    using Interfaces;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Moq;

    /// <summary>
    /// Defines the <seealso cref="Hisaab.Data.Tests.UserRepositoryTest"/> type.
    /// </summary>
    [TestClass]
    public class UserRepositoryTest
    {
        #region Query Tests

        /// <summary>
        /// Users the data manager get Users test with empty repository.
        /// </summary>
        [TestMethod]
        public void UserDataManagerQueryShouldReturnEmptyListWithEmptyRepository()
        {
            var mockObjectSet = new MockObjectSet<User>();
            var mockRepository = new Mock<IDatabase>();
            mockRepository.SetupGet(m => m.Users).Returns(mockObjectSet);
            var dao = new UserRepository(mockRepository.Object);
            var result = dao.Query(new User(), null, null);
            Assert.IsNotNull(result);
            Assert.AreEqual(0, result.Count());
            mockRepository.VerifyAll();
        }

        /// <summary>
        /// Users the data manager get Users test with non empty repository.
        /// </summary>
        [TestMethod]
        public void UserDataManagerQueryShouldReturnNonEmptyListWithNonEmptyRepository()
        {
            var mockObjectSet = new MockObjectSet<User>();
            mockObjectSet.AddObject(new User { Id = 1, Name = "User 1" });
            mockObjectSet.AddObject(new User { Id = 2, Name = "User 2" });
            mockObjectSet.AddObject(new User { Id = 3, Name = "User 3" });
            var mockRepository = new Mock<IDatabase>();
            mockRepository.SetupGet(m => m.Users).Returns(mockObjectSet);
            var dao = new UserRepository(mockRepository.Object);
            var result = dao.Query(new User(), null, null);
            Assert.IsNotNull(result);
            Assert.AreEqual(3, result.Count());
            Assert.AreEqual(1, result.ElementAt(0).Id);
            Assert.AreEqual("User 1", result.ElementAt(0).Name);
            Assert.AreEqual(2, result.ElementAt(1).Id);
            Assert.AreEqual("User 2", result.ElementAt(1).Name);
            Assert.AreEqual(3, result.ElementAt(2).Id);
            Assert.AreEqual("User 3", result.ElementAt(2).Name);
            mockRepository.VerifyAll();
        }

        #endregion Query Tests

        #region Filter Tests

        /// <summary>
        /// Users the data manager get Users test with empty repository.
        /// </summary>
        [TestMethod]
        public void UserDataManagerFilterShouldReturnEmptyListWithEmptyRepository()
        {
            var mockObjectSet = new MockObjectSet<User>();
            var mockRepository = new Mock<IDatabase>();
            mockRepository.SetupGet(m => m.Users).Returns(mockObjectSet);
            var dao = new UserRepository(mockRepository.Object);
            var result = dao.Filter(x => true, null, null);
            Assert.IsNotNull(result);
            Assert.AreEqual(0, result.Count());
            mockRepository.VerifyAll();
        }

        /// <summary>
        /// Users the data manager get Users test with non empty repository.
        /// </summary>
        [TestMethod]
        public void UserDataManagerFilterShouldReturnNonEmptyListWithNonEmptyRepository()
        {
            var mockObjectSet = new MockObjectSet<User>();
            mockObjectSet.AddObject(new User { Id = 1, Name = "User 1" });
            mockObjectSet.AddObject(new User { Id = 2, Name = "User 2" });
            mockObjectSet.AddObject(new User { Id = 3, Name = "User 3" });
            var mockRepository = new Mock<IDatabase>();
            mockRepository.SetupGet(m => m.Users).Returns(mockObjectSet);
            var dao = new UserRepository(mockRepository.Object);
            var result = dao.Filter(x => true, null, null);
            Assert.IsNotNull(result);
            Assert.AreEqual(3, result.Count());
            Assert.AreEqual(1, result.ElementAt(0).Id);
            Assert.AreEqual("User 1", result.ElementAt(0).Name);
            Assert.AreEqual(2, result.ElementAt(1).Id);
            Assert.AreEqual("User 2", result.ElementAt(1).Name);
            Assert.AreEqual(3, result.ElementAt(2).Id);
            Assert.AreEqual("User 3", result.ElementAt(2).Name);
            mockRepository.VerifyAll();
        }

        #endregion Filter Tests

        #region GetById Tests

        /// <summary>
        /// Get by id test with empty repository
        /// </summary>
        [TestMethod]
        public void UserDataManagerFindByIdShouldReturnNullWithEmptyRepository()
        {
            var mockObjectSet = new MockObjectSet<User>();
            var mockRepository = new Mock<IDatabase>();
            mockRepository.SetupGet(m => m.Users).Returns(mockObjectSet);
            var dao = new UserRepository(mockRepository.Object);
            var result = dao.FindById(1);
            Assert.IsNull(result);
            mockRepository.VerifyAll();
        }

        /// <summary>
        /// Get by id test with repository with records
        /// </summary>
        [TestMethod]
        public void UserDataManagerFindByIdShouldReturnMatchingUser()
        {
            var mockObjectSet = new MockObjectSet<User>();
            mockObjectSet.AddObject(new User { Id = 1, Name = "User 1" });
            mockObjectSet.AddObject(new User { Id = 2, Name = "User 2" });
            mockObjectSet.AddObject(new User { Id = 3, Name = "User 3" });
            var mockRepository = new Mock<IDatabase>();
            mockRepository.SetupGet(m => m.Users).Returns(mockObjectSet);
            var dao = new UserRepository(mockRepository.Object);
            var result = dao.FindById(2);
            Assert.IsNotNull(result);
            Assert.AreEqual(2, result.Id);
            Assert.AreEqual("User 2", result.Name);
            mockRepository.VerifyAll();
        }

        /// <summary>
        /// Users the data manager find by id should return null with no matching User.
        /// </summary>
        [TestMethod]
        public void UserDataManagerFindByIdShouldReturnNullWithNoMatchingUser()
        {
            var mockObjectSet = new MockObjectSet<User>();
            mockObjectSet.AddObject(new User { Id = 1, Name = "User 1" });
            mockObjectSet.AddObject(new User { Id = 2, Name = "User 2" });
            mockObjectSet.AddObject(new User { Id = 3, Name = "User 3" });
            var mockRepository = new Mock<IDatabase>();
            mockRepository.SetupGet(m => m.Users).Returns(mockObjectSet);
            var dao = new UserRepository(mockRepository.Object);
            var result = dao.FindById(20);
            Assert.IsNull(result);
            mockRepository.VerifyAll();
        }

        #endregion GetById Tests

        #region Insert Tests

        /// <summary>
        /// Email template dao insert test with empty repository
        /// </summary>
        [TestMethod]
        public void UserDataManagerInsertUserTestWithEmptyRepository()
        {
            var mockObjectSet = new MockObjectSet<User>();
            var mockRepository = new Mock<IDatabase>();
            mockRepository.SetupGet(m => m.Users).Returns(mockObjectSet);
            mockRepository.Setup(m => m.SaveChanges());
            mockRepository.Setup(m => m.Refresh(RefreshMode.StoreWins, It.IsAny<User>()));
            var dao = new UserRepository(mockRepository.Object);
            var result = dao.Add(new User { Id = 1, Name = "User 1" });
            Assert.AreEqual(1, mockObjectSet.Count());
            Assert.IsNotNull(result);
            mockRepository.VerifyAll();
        }

        /// <summary>
        /// Email template dao insert test with existing records in repository
        /// </summary>
        [TestMethod]
        public void UserDataManagerInsertUserTestWithNonEmptyRepository()
        {
            var mockObjectSet = new MockObjectSet<User>();
            mockObjectSet.AddObject(new User { Id = 1, Name = "User 1" });
            var mockRepository = new Mock<IDatabase>();
            mockRepository.SetupGet(m => m.Users).Returns(mockObjectSet);
            mockRepository.Setup(m => m.SaveChanges());
            mockRepository.Setup(m => m.Refresh(RefreshMode.StoreWins, It.IsAny<User>()));
            var dao = new UserRepository(mockRepository.Object);

            Assert.AreEqual(1, mockObjectSet.Count());

            var result = dao.Add(new User { Id = 2, Name = "User 2" });

            Assert.AreEqual(2, mockObjectSet.Count());
            Assert.IsNotNull(result);
            mockRepository.VerifyAll();
        }

        #endregion Insert Tests

        #region Udpate Tests

        /// <summary>
        /// Email template dao update test with no matching record
        /// </summary>
        [TestMethod]
        public void UserDataManagerUpdateUserTestWithNoMatchingRecord()
        {
            var mockObjectSet = new MockObjectSet<User>();
            mockObjectSet.AddObject(new User { Id = 1, Name = "User 1" });
            var mockRepository = new Mock<IDatabase>();
            mockRepository.SetupGet(m => m.Users).Returns(mockObjectSet);
            var dao = new UserRepository(mockRepository.Object);
            dao.Update(new User { Id = 2, Name = "User 2" });

            Assert.AreEqual(1, mockObjectSet.Count());
            mockRepository.VerifyAll();
        }

        /// <summary>
        /// Email template dao update test with matching record
        /// </summary>
        [TestMethod]
        public void UserDataManagerUpdateUserTestWithMatchingRecord()
        {
            var mockObjectSet = new MockObjectSet<User>();
            mockObjectSet.AddObject(new User { Id = 1, Name = "User 1" });
            var mockRepository = new Mock<IDatabase>();
            mockRepository.SetupGet(m => m.Users).Returns(mockObjectSet);
            mockRepository.Setup(m => m.SaveChanges()).Returns(1);

            var dao = new UserRepository(mockRepository.Object);
            dao.Update(new User { Id = 1, Name = "User 2" });

            Assert.AreEqual(1, mockObjectSet.Count());
            mockRepository.VerifyAll();
        }

        #endregion Udpate Tests

        #region Delete Tests

        /// <summary>
        /// Email template dao delete test with no matching record
        /// </summary>
        [TestMethod]
        public void UserDataManagerDeleteUserTestWithNoMatchingRecord()
        {
            var mockObjectSet = new MockObjectSet<User>();
            mockObjectSet.AddObject(new User { Id = 1, Name = "User 1" });
            var mockRepository = new Mock<IDatabase>();
            mockRepository.SetupGet(m => m.Users).Returns(mockObjectSet);
            var dao = new UserRepository(mockRepository.Object);
            dao.Delete(new User { Id = 2 });

            Assert.AreEqual(1, mockObjectSet.Count());
        }

        /// <summary>
        /// Email template dao delete test with matching record
        /// </summary>
        [TestMethod]
        public void UserDataManagerDeleteUserTestWithMatchingRecord()
        {
            var mockObjectSet = new MockObjectSet<User>();
            mockObjectSet.AddObject(new User { Id = 1, Name = "User 1" });
            var mockRepository = new Mock<IDatabase>();
            mockRepository.SetupGet(m => m.Users).Returns(mockObjectSet);
            var dao = new UserRepository(mockRepository.Object);
            dao.Delete(new User { Id = 1 });

            Assert.AreEqual(0, mockObjectSet.Count());
        }

        #endregion Delete Tests

        #region ValidateUser

        /// <summary>
        /// Validates the useer should return negative value if user name is null.
        /// </summary>
        [TestMethod]
        public void ValidateUserShouldReturnNegativeValueIfUserNameIsNull()
        {
            var mockObjectSet = new MockObjectSet<User>();
            mockObjectSet.AddObject(new User { Id = 1, Name = "User1", Password = "user1pwd" });
            var mockRepository = new Mock<IDatabase>();
            mockRepository.SetupGet(m => m.Users).Returns(mockObjectSet);
            var dao = new UserRepository(mockRepository.Object);
            var result = dao.ValidateUser(null, "some password");
            Assert.IsTrue(result < 0);
        }

        /// <summary>
        /// Validates the useer should return negative value if user name is empty.
        /// </summary>
        [TestMethod]
        public void ValidateUserShouldReturnNegativeValueIfUserNameIsEmpty()
        {
            var mockObjectSet = new MockObjectSet<User>();
            mockObjectSet.AddObject(new User { Id = 1, Name = "User1", Password = "user1pwd" });
            var mockRepository = new Mock<IDatabase>();
            mockRepository.SetupGet(m => m.Users).Returns(mockObjectSet);
            var dao = new UserRepository(mockRepository.Object);
            var result = dao.ValidateUser(string.Empty, "some password");
            Assert.IsTrue(result < 0);
        }

        /// <summary>
        /// Validates the useer should return negative value if user name is white space.
        /// </summary>
        [TestMethod]
        public void ValidateUserShouldReturnNegativeValueIfUserNameIsWhiteSpace()
        {
            var mockObjectSet = new MockObjectSet<User>();
            mockObjectSet.AddObject(new User { Id = 1, Name = "User1", Password = "user1pwd" });
            var mockRepository = new Mock<IDatabase>();
            mockRepository.SetupGet(m => m.Users).Returns(mockObjectSet);
            var dao = new UserRepository(mockRepository.Object);
            var result = dao.ValidateUser("  ", "some password");
            Assert.IsTrue(result < 0);
        }

        /// <summary>
        /// Validates the useer should return negative value if user not found.
        /// </summary>
        [TestMethod]
        public void ValidateUserShouldReturnNegativeValueIfUserNotFound()
        {
            var mockObjectSet = new MockObjectSet<User>();
            mockObjectSet.AddObject(new User { Id = 1, Name = "User1", Password = "user1pwd" });
            var mockRepository = new Mock<IDatabase>();
            mockRepository.SetupGet(m => m.Users).Returns(mockObjectSet);
            var dao = new UserRepository(mockRepository.Object);
            var result = dao.ValidateUser("Somename", "some password");
            Assert.IsTrue(result < 0);
        }

        /// <summary>
        /// Validates the useer should return negative value if password wrong.
        /// </summary>
        [TestMethod]
        public void ValidateUserShouldReturnNegativeValueIfPasswordWrong()
        {
            var mockObjectSet = new MockObjectSet<User>();
            mockObjectSet.AddObject(new User { Id = 165, Name = "User1", Password = "user1pwd" });
            var mockRepository = new Mock<IDatabase>();
            mockRepository.SetupGet(m => m.Users).Returns(mockObjectSet);
            var dao = new UserRepository(mockRepository.Object);
            var result = dao.ValidateUser("User1", "somepassword");
            Assert.IsTrue(result < 0);
        }

        /// <summary>
        /// Validates the useer should return negative value if password is wrong case.
        /// </summary>
        [TestMethod]
        public void ValidateUserShouldReturnNegativeValueIfPasswordIsWrongCase()
        {
            var mockObjectSet = new MockObjectSet<User>();
            mockObjectSet.AddObject(new User { Id = 165, Name = "User1", Password = "user1pwd" });
            var mockRepository = new Mock<IDatabase>();
            mockRepository.SetupGet(m => m.Users).Returns(mockObjectSet);
            var dao = new UserRepository(mockRepository.Object);
            var result = dao.ValidateUser("User1", "user1pwD");
            Assert.IsTrue(result < 0);
        }

        /// <summary>
        /// Validates the useer should return usewr id if valid user and password.
        /// </summary>
        [TestMethod]
        public void ValidateUserShouldReturnUsewrIdIfValidUserAndPassword()
        {
            var mockObjectSet = new MockObjectSet<User>();
            mockObjectSet.AddObject(new User { Id = 789, Name = "User1", Password = "user1pwd" });
            var mockRepository = new Mock<IDatabase>();
            mockRepository.SetupGet(m => m.Users).Returns(mockObjectSet);
            var dao = new UserRepository(mockRepository.Object);
            var result = dao.ValidateUser("User1", "user1pwd");
            Assert.AreEqual(789, result);
        }

        /// <summary>
        /// Validates the useer should return usewr id if valid user with different case.
        /// </summary>
        [TestMethod]
        public void ValidateUserShouldReturnUsewrIdIfValidUserWithDifferentCase()
        {
            var mockObjectSet = new MockObjectSet<User>();
            mockObjectSet.AddObject(new User { Id = 165, Name = "User1", Password = "user1pwd" });
            var mockRepository = new Mock<IDatabase>();
            mockRepository.SetupGet(m => m.Users).Returns(mockObjectSet);
            var dao = new UserRepository(mockRepository.Object);
            var result = dao.ValidateUser("USER1", "user1pwd");
            Assert.AreEqual(165, result);
        }

        #endregion ValidateUser
    }
}